package com.skywolf.chem.match.pay.alibaba.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
import com.ijpay.alipay.AliPayApi;
import com.ijpay.alipay.AliPayApiConfig;
import com.ijpay.alipay.AliPayApiConfigKit;
import com.skywolf.chem.common.sysconfig.exception.BizException;
import com.skywolf.chem.match.common.constants.MatchConstants;
import com.skywolf.chem.match.common.enums.MatchApplyRecordStatusEnum;
import com.skywolf.chem.match.common.enums.RefundStatusEnum;
import com.skywolf.chem.match.entity.ApplyUserRecord;
import com.skywolf.chem.match.entity.GroupInfo;
import com.skywolf.chem.match.entity.Order;
import com.skywolf.chem.match.entity.RefundOrder;
import com.skywolf.chem.match.pay.alibaba.config.AliPayProperties;
import com.skywolf.chem.match.pay.alibaba.service.AliPayRefundService;
import com.skywolf.chem.match.pay.wx.config.WxPayProperties;
import com.skywolf.chem.match.service.IApplyUserRecordService;
import com.skywolf.chem.match.service.IGroupInfoService;
import com.skywolf.chem.match.service.IOrderService;
import com.skywolf.chem.match.service.IRefundOrderService;
import com.skywolf.chem.match.utils.StringUtils;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;

/**
 * @Author sj
 * Date on 2021/10/11  16:14
 * @Version 1.0
 */
@Service
@AllArgsConstructor
public class AliPayRefundServiceImpl implements AliPayRefundService {
    private final IOrderService orderService;

    private final IGroupInfoService iGroupInfoService;

    private final AliPayProperties aliPayProperties;

    private final AliPayApiConfig aliPayApiConfig;

    private final IRefundOrderService refundOrderService;

    private final IApplyUserRecordService iApplyUserRecordService;

    private final IGroupInfoService groupInfoService;

    private final RedisTemplate<String, Object> redisTemplate;

    private final IApplyUserRecordService applyUserRecordService;

    @Override
    public void wxPayRefund(Long orderId, Long applyUserId) throws AlipayApiException {

        Order order = orderService.getById(orderId);
        GroupInfo groupInfo = iGroupInfoService.getById(order.getMatchGroupId());
        if (StringUtils.isEmpty(order)) {
            throw new BizException("订单不存在！");
        }
        ApplyUserRecord record = iApplyUserRecordService.getById(applyUserId);
        if (StringUtils.isEmpty(record)) {
            throw new BizException("取消报名用户不存在！");
        }
        if (record.getApplyStatus().equals(MatchApplyRecordStatusEnum.APPLY_REFUND.getStatus()) ||
                record.getApplyStatus().equals(MatchApplyRecordStatusEnum.APPLY_NORMAL_STATUS.getStatus()) ||
                record.getApplyStatus().equals(MatchApplyRecordStatusEnum.UNPAID.getStatus())) {
            throw new BizException("当前用户不满足退款条件");
        }
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        // 用户id前补零保证五位，对超出五位的保留后五位
        String userIdFilledZero = String.format("%05d", order.getMatchUserId());
        String fiveDigitsUserId = userIdFilledZero.substring(userIdFilledZero.length() - 5);
        // 在前面加上wxo（wx_refund）等前缀是为了人工可以快速分辨订单号是下单还是退款、来自哪家支付机构等
        // 将时间戳+3位随机数+五位id组成商户退款订单号
        String outRefundNo = "wx_refund_" + System.currentTimeMillis() + RandomUtil.randomNumbers(3) + fiveDigitsUserId;
        model.setOutTradeNo(order.getOutTradeNo());
        model.setRefundAmount(groupInfo.getPrice().toString());
        model.setRefundReason("取消报名退款");
        AliPayApiConfigKit.setThreadLocalAliPayApiConfig(aliPayApiConfig);
        AlipayTradeRefundResponse refundResponse = AliPayApi.tradeRefundToResponse(model);
        //创建退款子订单
        RefundOrder refundOrder = new RefundOrder();
        refundOrder.setOrderSn(outRefundNo);
        refundOrder.setParentOrderId(orderId);
        refundOrder.setParentOrderSn(order.getOrderSn());
        refundOrder.setRefundPayType(order.getPayType());
        refundOrder.setApplyUserId(applyUserId);
        refundOrder.setRefundPrice(groupInfo.getPrice().multiply(new BigDecimal(100)).longValue());
        if (refundResponse.getCode().equals("10000") && refundResponse.getMsg().equals("Success")) {
            refundOrder.setRefundSuccessTime(LocalDateTime.ofInstant(refundResponse.getGmtRefundPay().toInstant(), ZoneId.systemDefault()));
            refundOrder.setRefundStatus(RefundStatusEnum.SUCCESS.getStatus());
            //给指定活动指定组别更新库存
            groupInfoService.update(new LambdaUpdateWrapper<GroupInfo>()
                    .eq(GroupInfo::getId, order.getMatchGroupId())
                    // 扣减库存
                    .setSql("stock = stock + " + 1));
            groupInfo = iGroupInfoService.getById(order.getMatchGroupId());
            // 写->缓存
            redisTemplate.opsForValue().set(MatchConstants.LOCKED_STOCK_PREFIX + order.getMatchGroupId(), String.valueOf(groupInfo.getStock()));
            //修改报名人状态
            applyUserRecordService.update(new LambdaUpdateWrapper<ApplyUserRecord>()
                    .set(ApplyUserRecord::getApplyStatus, MatchApplyRecordStatusEnum.APPLY_REFUND.getStatus()).eq(ApplyUserRecord::getId, applyUserId));
            //更新订单报名人数
            orderService.update(new LambdaUpdateWrapper<Order>().eq(Order::getId, order.getId()).setSql("total_quantity=total_quantity-1"));
        } else {
            refundOrder.setRefundStatus(RefundStatusEnum.REFUNDCLOSE.getStatus());
            //修改报名人状态
            applyUserRecordService.update(new LambdaUpdateWrapper<ApplyUserRecord>()
                    .set(ApplyUserRecord::getApplyStatus, MatchApplyRecordStatusEnum.APPLY_REFUND_ERR.getStatus()).eq(ApplyUserRecord::getId, applyUserId));
            throw new BizException(refundResponse.getSubMsg());
        }

    }
}
